Swift Collections
在Swift中自定义一个CollectionType或者是SequenceType类型的数据结构需要实现对应的协议。这里首先给出一个自定义的SequenceType类型的数据结构,然后我们再来逐步分解代码解析之。
1 | extension Array { |
Sequence在Swift中的定义:
A type that can be ietrated in a `for...in` loop
要成为一个Sequence,必须实现SequenceType协议,该协议要求实现一个方法以返回一个Generator,而一个Generator又实现了一个GeneratorType的协议,它封装了我们自定的Sequence类型里面的数据,并且保留了迭代的过程。
在上述代码中,我们首先定一个一个ArrayGenerator作为我们的Generator,然后在我们自定的Section类型中实现generate方法,返回我们的Generator,这样我们就可以在for…in中使用我们的Section了。
1 | let elements = ["hello", "world", "haha"] |
上述代码中,for…in和while循环实际上是一样的。
在实现SequenceType以后,我们还自动获得了许多方法,比如:
1 | section.sort() // ["haha", "hello", "world"] |
因为字符串是可比较的,所以上述三个方法均可返回正确的数值。
在讨论SequenceType之后,我们来看看CollectionType的定义:
1 | protocol CollectionType: Indexable, SequenceType { |
所以要定义一个CollectionType类型的数据结构,只要我们的Section再实现Indexable协议即可。我们改写Section的代码。
1 | struct Section<T> : CollectionType { |
由于遵守Indexable协议的类型必须实现一个下标脚本,其返回值是一个non-optinal的值,所以我们需要改写Section为上述形式。
至此我们就创建了一个CollectionType类型的Section。
在这里需要额外说一点:在我们用下标语法来取值的时候,swift中的array和dictionary的行为是不一致的,举个栗子:
1 | let arr = ["h", "e", "l"]; |
字典和数组都是实现了CollectionType协议,换言之,它们都实现了返回一个non-optional的下表脚本,那为什么上述代码中字典返回nil呢?我们看字典的下表语法:
1 | struct Dictionary<Key : Hashable, Value> { |
实际上在字典中返回non-optional的是第二个脚本。所以当我们按照以下方法来操作字典时就会报错。
1 | var startIndex = dict.startIndex |
Indexable要求返回一个non-optional的值仅仅为了性能,毕竟直接crash比检查一个index的有效性快。